package com.JUC.cha09.hw;

import java.util.HashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAccumulator;
import java.util.concurrent.atomic.LongAdder;

class ClickNumber {//资源类

    int number = 0;

    public synchronized void addBySynchronized() {
        number++;
    }

    AtomicLong atomicLong = new AtomicLong(0);

    public void addByAtomicLong() {
        atomicLong.getAndIncrement();
    }

    LongAdder longAdder = new LongAdder();

    public void addByLongAdder() {
        longAdder.increment();
    }

    LongAccumulator longAccumulator = new LongAccumulator((x, y) -> x + y, 0);

    public void addByLongAccumulator() {
        longAccumulator.accumulate(1);
    }
}

/**
 * 需求50个线程，每个线程执行100w次，总点赞数出来
 * synchronized
 * AtomicLong
 * LongAdder
 * LongAccumulator
 */
public class AccumulatorCompareDemo {

    private static final int _1w = 10000;
    private static final int Number = 50;


    public static void main(String[] args) throws InterruptedException {
        ClickNumber clickNumber = new ClickNumber();
        long startTime;
        long endTime;

        CountDownLatch countDownLatch1 = new CountDownLatch(Number);
        CountDownLatch countDownLatch2 = new CountDownLatch(Number);
        CountDownLatch countDownLatch3 = new CountDownLatch(Number);
        CountDownLatch countDownLatch4 = new CountDownLatch(Number);

        startTime = System.currentTimeMillis();
        for (int i = 0; i < Number; i++) {
            new Thread(() -> {
                try {
                    for (int j = 0; j < 100 * _1w; j++) {
                        clickNumber.addBySynchronized();
                    }
                } finally {
                    countDownLatch1.countDown();
                }
            }, String.valueOf(i)).start();

        }
        countDownLatch1.await();
        endTime = System.currentTimeMillis();
        System.out.println("---- costTime：" + "\t" + (endTime - startTime) + "毫秒。" + "\taddBySynchronized" + "结果：" + "\t" + clickNumber.number);

        startTime = System.currentTimeMillis();
        for (int i = 0; i < Number; i++) {
            new Thread(() -> {
                try {
                    for (int j = 0; j < 100 * _1w; j++) {
                        clickNumber.addByAtomicLong();
                    }
                } finally {
                    countDownLatch2.countDown();
                }
            }, String.valueOf(i)).start();

        }
        countDownLatch2.await();
        endTime = System.currentTimeMillis();
        System.out.println("---- costTime：" + "\t" + (endTime - startTime) + "毫秒。" + "\taddByAtomicLong" + "结果：" + "\t" + clickNumber.atomicLong.get());

        startTime = System.currentTimeMillis();
        for (int i = 0; i < Number; i++) {
            new Thread(() -> {
                try {
                    for (int j = 0; j < 100 * _1w; j++) {
                        clickNumber.addByLongAdder();
                    }
                } finally {
                    countDownLatch3.countDown();
                }
            }, String.valueOf(i)).start();
        }
        countDownLatch3.await();
        endTime = System.currentTimeMillis();
        System.out.println("---- costTime：" + "\t" + (endTime - startTime) + "毫秒。" + "\taddByLongAdder" + "结果：" + "\t" + clickNumber.longAdder.sum());

        startTime = System.currentTimeMillis();
        for (int i = 0; i < Number; i++) {
            new Thread(() -> {
                try {
                    for (int j = 0; j < 100 * _1w; j++) {
                        clickNumber.addByLongAccumulator();
                    }
                } finally {
                    countDownLatch4.countDown();
                }
            }, String.valueOf(i)).start();

        }
        countDownLatch4.await();
        endTime = System.currentTimeMillis();
        System.out.println("---- costTime：" + "\t" + (endTime - startTime) + "毫秒。" + "\taddByLongAccumulator" + "结果：" + "\t" + clickNumber.longAccumulator.get());
    }
}
